package com.ruoyi.patient.controller;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.patient.entity.LoginPatient;
import com.ruoyi.patient.entity.PatientLoginBody;
import com.ruoyi.patient.entity.login.WechatUser;
import com.ruoyi.patient.service.PatientLoginService;
import com.ruoyi.patient.service.PatientTokenService;
import com.ruoyi.patient.utils.MyX509TrustManager;
import com.ruoyi.patient.utils.PatientTokenFilter;
import com.ruoyi.patient.utils.WechatUtil;
import com.ruoyi.service.domain.ServiceAppinfo;
import com.ruoyi.service.service.IServiceAppinfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.ConnectException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.ruoyi.common.core.domain.AjaxResult.error;


/**
 * 登录控制
 * 
 * @author ZDL
 */
@RestController
@RequestMapping("/appPatient")
public class PatientLoginController
{
    @Autowired
    private PatientLoginService loginService;

    @Autowired
    private PatientTokenService tokenService;

    @Autowired
    private IServiceAppinfoService appinfoService;

    @Qualifier("patientRestTemplate")
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private PatientTokenFilter patientTokenFilter;

    //@PostMapping("/wx/getPhone")
    //public R getPhone(@RequestParam(value = "code", required = false) String code) {
    //    // 获取token
    //    String token_url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appid, secret);
    //    JSONObject token = JSON.parseObject(HttpUtil.get(token_url));
    //
    //    // 使用前端code获取手机号码 参数为json格式
    //    String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + token.getString("access_token");
    //    Map<String, String> paramMap = new HashMap<>();
    //    paramMap.put("code", code);
    //    HttpHeaders headers = new HttpHeaders();
    //    HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(paramMap, headers);
    //    System.out.println(httpEntity);
    //    ResponseEntity<Object> response = restTemplate.postForEntity(url, httpEntity, Object.class);
    //    String phoneNumber = response.getBody().toString();
    //    return R.ok().message("获取手机号码成功.").data(response.getBody());
    //}


    /**
     * 微信登录方法
     *
     * @param
     * @return 结果
     */

    //@RequestParam(value = "rawData", required = false) String rawData,
    //@RequestParam(value = "signature", required = false) String signature
    @PostMapping("/wxLoginPatient")
    public AjaxResult wxLogin(@RequestBody Map<String, String> reqBody)
    {
        String code = reqBody.get("code");
        String phoneCode = reqBody.get("phoneCode");

        AjaxResult ajax = AjaxResult.success();
        //JSONObject rawDataJson = JSON.parseObject(rawData);
        ServiceAppinfo appinfo = appinfoService.selectServiceAppinfoByAppinfoId(4L);

        JSONObject sessionKeyOpenId = WechatUtil.getSessionKeyOrOpenId(code, appinfo.getAppinfoAppid(), appinfo.getAppinfoSecret());
        String openid = sessionKeyOpenId.getString("openid");
        String sessionKey = sessionKeyOpenId.getString("session_key");

        if (StringUtils.isEmpty(openid)) {
            return error("用户信息过期，请重新登录！");
        }

        String token = loginService.wxLogin(code, openid, sessionKey, appinfo.getAppinfoAppid(), appinfo.getAppinfoSecret());

        LoginPatient oldPatient = tokenService.getLoginUserByTk(token);
        //if (oldPatient.getUser().getUsersTelephone() == null){
        if (true){
            // 获取token
            String token_url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appinfo.getAppinfoAppid(), appinfo.getAppinfoSecret());
            JSONObject tokenInfo = JSON.parseObject(HttpUtil.get(token_url));
            String accessToken = tokenInfo.getString("access_token");
            // 使用前端code                                                                                             获取手机号码 参数为json格式
            String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + tokenInfo.getString("access_token");
            Map<String, String> paramMap = new HashMap<>();
            paramMap.put("code", phoneCode);
            HttpHeaders headers = new HttpHeaders();
            HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(paramMap, headers);
            System.out.println(httpEntity);
            ResponseEntity<Object> response = restTemplate.postForEntity(url, httpEntity, Object.class);

            String body = String.valueOf(response.getBody());// 解析JSON字符串
            // 定义一个正则表达式来匹配 phoneNumber
            Pattern pattern = Pattern.compile("phoneNumber=(\\d+)");
            Matcher matcher = pattern.matcher(body);
            if (matcher.find()) {
                String phoneNumber = matcher.group(1); // 获取括号中的数字

                // 根据传入的accessToken以及openId拼接出访问微信定义的端口并获取用户信息的URL
                String infoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token="+accessToken+"&openid="+openid+"&lang=zh_CN";
                // 访问该URL获取用户信息json 字符串
                String userStr = httpsRequest(infoUrl, "GET", null);
                WechatUser user = new WechatUser();
                ObjectMapper objectMapper = new ObjectMapper();
                try {
                    // 将json字符串转换成相应对象
                    user = objectMapper.readValue(userStr, WechatUser.class);
                    user.setNickName(phoneNumber);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (user == null){
                    return error("获取用户信息失败！");
                }
                if ((oldPatient.getUser().getUsersTelephone() != null) && (!phoneNumber.equals((oldPatient.getUser().getUsersTelephone())) )){
                    Boolean result = loginService.wxPhone(user, openid, phoneNumber);
                    if (!result) {
                        return AjaxResult.success("绑定手机号失败.");
                    }
                }else if ((oldPatient.getUser().getUsersTelephone() == null)){
                    Boolean result = loginService.wxPhone(user, openid, phoneNumber);
                    if (!result) {
                        return AjaxResult.success("绑定手机号失败.");
                    }
                }

            } else {
                return error("手机号获取失败！");
            }

            token = loginService.wxLogin(code, openid, sessionKey, appinfo.getAppinfoAppid(), appinfo.getAppinfoSecret());
        }

        oldPatient = tokenService.getLoginUserByTk(token);

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put(Constants.TOKEN, token);
        dataMap.put("userId", oldPatient.getUserId());
        dataMap.put("nickName", oldPatient.getUser().getUsersName());
        dataMap.put("avatarUrl", oldPatient.getUser().getNurseAvatar());
        dataMap.put("phone", oldPatient.getUser().getUsersTelephone());
        dataMap.put("openid", openid);
        dataMap.put("gender", oldPatient.getUser().getNurseSex());
        dataMap.put("createTime", oldPatient.getUser().getUsersCreateTime());
        dataMap.put("lastLoginTime", oldPatient.getUser().getUsersCurrentlogintime());
        dataMap.put("status", null);
        dataMap.put("phoneFlag", oldPatient.getUser().getUsersTelephone()==null ? false : true);

        ajax.put("data", dataMap);
        return ajax;
        //String signature2 = DigestUtils.sha1Hex(rawData + sessionKey);
        //if (!signature.equals(signature2)) {
        //    return ajax.error("签名校验失败");
        //}
        //LambdaQueryWrapper<User> lqw = Wrappers.lambdaQuery();
        //lqw.eq(User::getOpenId, openid);
        //User user = userService.getOne(lqw);
        //if (user == null) {
        //    String nickName = rawDataJson.getString("nickName");
            //String avatarUrl = rawDataJson.getString("avatarUrl");
            //user = new User();
            //user.setOpenId(openid);
            //user.setAvatar(avatarUrl);
            //user.setNickName(nickName);
            //userService.save(user);
        //}

    }

    /**
     * 微信登录方法
     *
     * @param
     * @return 结果
     */

    //@RequestParam(value = "rawData", required = false) String rawData,
    //@RequestParam(value = "signature", required = false) String signature
    @PostMapping("/wxLoginCheck")
    public AjaxResult wxLoginCheck(HttpServletRequest request)
    {
        try {
            if(!patientTokenFilter.doFilterInternal(request)) {
                AjaxResult ajaxResult = new AjaxResult();
                ajaxResult.put("code", 401);
                ajaxResult.put("msg", "用户信息过期，请重新登录");
                return ajaxResult;
            }
            LoginPatient oldPatient = tokenService.getLoginUser(request);
            if (oldPatient.getUserId() == null ) {
                return AjaxResult.warn("用户信息错误");
            }
            return AjaxResult.success("用户登录有效");

        }catch (Exception e){
            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 微信登录信息维护方法
     *
     * @param
     * @return 结果
     */

    //@RequestParam(value = "rawData", required = false) String rawData,
    //@RequestParam(value = "signature", required = false) String signature
    @PostMapping("/wxInfoPatient")
    public AjaxResult wxInfoPatient(@RequestBody Map<String, String> reqBody)
    {

        String code = reqBody.get("code");
        String openId = reqBody.get("openId");

        AjaxResult ajax = AjaxResult.success();
        ServiceAppinfo appinfo = appinfoService.selectServiceAppinfoByAppinfoId(4L);

        // 获取token
        String token_url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appinfo.getAppinfoAppid(), appinfo.getAppinfoSecret());
        JSONObject token = JSON.parseObject(HttpUtil.get(token_url));
        String accessToken = token.getString("access_token");
        // 使用前端code获取手机号码 参数为json格式
        String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + token.getString("access_token");
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("code", code);
        HttpHeaders headers = new HttpHeaders();
        HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(paramMap, headers);
        System.out.println(httpEntity);
        ResponseEntity<Object> response = restTemplate.postForEntity(url, httpEntity, Object.class);

        String body = String.valueOf(response.getBody());// 解析JSON字符串
        // 定义一个正则表达式来匹配 phoneNumber
        Pattern pattern = Pattern.compile("phoneNumber=(\\d+)");
        Matcher matcher = pattern.matcher(body);
        if (matcher.find()) {
            String phoneNumber = matcher.group(1); // 获取括号中的数字

            // 根据传入的accessToken以及openId拼接出访问微信定义的端口并获取用户信息的URL
            String infoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token="+accessToken+"&openid="+openId+"&lang=zh_CN";
            // 访问该URL获取用户信息json 字符串
            String userStr = httpsRequest(infoUrl, "GET", null);
            WechatUser user = new WechatUser();
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                // 将json字符串转换成相应对象
                user = objectMapper.readValue(userStr, WechatUser.class);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (user == null){
                return error("获取用户信息失败！");
            }
            Boolean result = loginService.wxPhone(user, openId, phoneNumber);
            if (result) {
                return AjaxResult.success("绑定手机号成功.");
            } else {
                return error("绑定手机号失败.");
            }
        } else {
            return error("手机号获取失败！");
        }

    }

    /**
     * 发起https请求并获取结果
     *
     * @param requestUrl    请求地址
     * @param requestMethod 请求方式（GET、POST）
     * @param outputStr     提交的数据
     * @return 返回的json字符串
     */
    public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        StringBuffer buffer = new StringBuffer();
        try {
            // 创建SSLContext对象，并使用我们指定的信任管理器初始化
            TrustManager[] trustManagers = {new MyX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, trustManagers, new java.security.SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL url = new URL(requestUrl);
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
            httpUrlConn.setSSLSocketFactory(ssf);

            httpUrlConn.setDoOutput(true);
            httpUrlConn.setDoInput(true);
            httpUrlConn.setUseCaches(false);
            // 设置请求方式（GET/POST）
            httpUrlConn.setRequestMethod(requestMethod);

            if ("GET".equalsIgnoreCase(requestMethod))
                httpUrlConn.connect();

            // 当有数据需要提交时
            if (null != outputStr) {
                OutputStream outputStream = httpUrlConn.getOutputStream();
                // 注意编码格式，防止中文乱码
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }

            // 将返回的输入流转换成字符串
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }

            // 释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            httpUrlConn.disconnect();
        } catch (ConnectException ce) {
            error("Weixin server connection timed out.");
        } catch (Exception e) {
            error("https request error:{}", e);
        }
        //最后将获取到的数据返回
        return buffer.toString();
    }



    /**
     * 登录方法
     * 
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/loginPatient")
    public AjaxResult login(@RequestBody PatientLoginBody loginBody, HttpServletRequest request)
    {
        LoginPatient oldLogin = tokenService.getLoginUser(request);
        if (oldLogin != null){
            return error("请先退出当前账号！");
        }
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        String token = loginService.loginApp(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
                loginBody.getUuid(), 1);
        LoginPatient oldPatient = tokenService.getLoginUserByTk(token);

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put(Constants.TOKEN, token);
        dataMap.put("userId", oldPatient.getUserId());
        dataMap.put("nickName", oldPatient.getUser().getUsersName());
        dataMap.put("avatarUrl", oldPatient.getUser().getNurseAvatar());
        dataMap.put("phone", oldPatient.getUser().getUsersTelephone());
        dataMap.put("openid", null);
        dataMap.put("gender", oldPatient.getUser().getNurseSex());
        dataMap.put("createTime", oldPatient.getUser().getUsersCreateTime());
        dataMap.put("lastLoginTime", oldPatient.getUser().getUsersCurrentlogintime());
        dataMap.put("status", null);

        ajax.put("data", dataMap);
        return ajax;
    }

    ///**
    // * 获取用户信息
    // *
    // * @return 用户信息
    // */
    //@GetMapping("getInfo")
    //public AjaxResult getInfo()
    //{
    //    SysUser user = SecurityUtils.getLoginUser().getUser();
    //    // 角色集合
    //    Set<String> roles = permissionService.getRolePermission(user);
    //    // 权限集合
    //    Set<String> permissions = permissionService.getMenuPermission(user);
    //    AjaxResult ajax = AjaxResult.success();
    //    ajax.put("user", user);
    //    ajax.put("roles", roles);
    //    ajax.put("permissions", permissions);
    //    return ajax;
    //}
    //
    ///**
    // * 获取路由信息
    // *
    // * @return 路由信息
    // */
    //@GetMapping("getRouters")
    //public AjaxResult getRouters()
    //{
    //    Long userId = SecurityUtils.getUserId();
    //    List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
    //    return AjaxResult.success(menuService.buildMenus(menus));
    //}
    /**
     * 退出登录方法
     * @return 结果
     */
    @Anonymous
    @PostMapping("/logoutPatient")
    public AjaxResult onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException, ServletException
    {
        AjaxResult result = new AjaxResult(200, "退出成功！");
        try {
        LoginPatient loginUser = tokenService.getLoginUser(request);
        if (StringUtils.isNotNull(loginUser))
        {
            String userName = loginUser.getUsername();
            // 删除用户缓存记录
            tokenService.delLoginUser(loginUser.getToken());
            // 记录用户退出日志
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, MessageUtils.message("user.logout.success")));
        }
        //ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success(MessageUtils.message("user.logout.success"))));
        }catch (Exception e){
            result = new AjaxResult(400, e.getMessage());
        }finally {
            return result;
        }
    }
}
